package com.gitee.jnxj.nraft.autoconfigure;

import com.gitee.jnxj.nraft.common.core.Node;
import com.gitee.jnxj.nraft.common.core.Peer;
import com.gitee.jnxj.nraft.common.core.PeerAddress;
import com.gitee.jnxj.nraft.common.log.LogEntry;
import com.gitee.jnxj.nraft.election.Election;
import com.gitee.jnxj.nraft.logreply.LogManager;
import com.gitee.jnxj.nrpc.spring.boot.autoconfigure.config.RpcServerConfig;
import lombok.Getter;
import lombok.NonNull;
import org.springframework.beans.BeansException;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 江南小俊
 * @since 2021/7/12
 **/
@Configuration
@EnableConfigurationProperties({RpcServerConfig.class, NRaftConfig.class})
@ComponentScan("com.gitee.jnxj.nraft")
@ConditionalOnExpression("'${nrpc.server.address:false}' ne 'false' && '${nrpc.server.port:false}' ne 'false' " +
                                 "&&'${nrpc.register.connectString:false}' ne 'false' && '${nraft.log_path}' ne false")
public class NRaftAutoConfiguration implements ApplicationContextAware {
    @Getter
    private static ApplicationContext applicationContext;
    @Resource
    private RpcServerConfig rpcServerConfig;
    @Resource
    private NRaftConfig nRaftConfig;

    @Bean(initMethod = "init")
    public Election election() {
        List<Peer> peers = new ArrayList<>();
        @NonNull Node node = Node.builder()
                .commitIndex(0)
                .lastApplied(0)
                .currentTerm(checkCurrentTerm())
                .votedFor(checkVotedFor())
                .type(Node.NodeType.FOLLOWER)
                .peers(peers)
                .build();
        for (int i = 0; i < nRaftConfig.getNodes().size(); i++) {
            NRaft nRaft = nRaftConfig.getNodes().get(i);
            if (rpcServerConfig.getAddress().equals(nRaft.getAddress()) && rpcServerConfig.getPort().equals(nRaft.getPort())) {
                node.setId(i + 1);
            } else {
                peers.add(Peer.builder()
                        .id(i + 1)
                        .nextIndex(1)
                        .matchIndex(0)
                        .peerAddress(PeerAddress.builder()
                                .address(nRaft.getAddress())
                                .port(nRaft.getPort()).build())
                        .build());
            }
        }
        return new Election(node);
    }

    /**
     * 查持久化的VotedFor
     *
     * @return java.lang.Integer
     * @author Jim
     * @since 2021/7/14 下午4:41
     **/

    private Integer checkVotedFor() {
        return null;
    }

    /**
     * 查持久化的CurrentTerm
     *
     * @return long
     * @author Jim
     * @since 2021/7/14 下午4:41
     **/

    private long checkCurrentTerm() {
        return 0;
    }


    @Bean(initMethod = "init")
    public LogManager logManager() {
        return new LogManager(nRaftConfig.getLog_path() + rpcServerConfig.getPort());
    }

    private long checkCommit() {
        LogManager logManager = logManager();
        LogEntry entry = logManager.getLastEntryOfCommit();
        if (entry == null) return 0;
        return entry.getKey().getKeyId();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        NRaftAutoConfiguration.applicationContext = applicationContext;
    }
}
